package com.etlmaster.executor.steps.extract;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.springframework.util.StringUtils;

import com.etlmaster.core.DataSourceDefine;
import com.etlmaster.core.DataSourceHolder;
import com.etlmaster.crypto.DesCipher;
import com.etlmaster.executor.Step;
import com.etlmaster.executor.StepMeta;
import com.etlmaster.executor.annotation.StepInstruction;
import com.etlmaster.executor.utils.DataCollectionUtils;
import com.etlmaster.executor.utils.DpExecutorUtils;
import com.etlmaster.executor.utils.Shell;
import com.etlmaster.executor.utils.SimpleKey;
import com.etlmaster.executor.utils.StepState;
import com.etlmaster.jdbc.JdbcTemplate;


/**
 * @author Lizq
 * @date 2016-06-29
 */
@StepInstruction("gbaseExport")

public class GbaseExportStep extends Step {
	
	/**
	 * 远程导出标记
	 */
	private static final String REMOTE_EXPORT_FLAG="rmt:";
	
	/**
	 * jdbc IP地址匹配
	 */
	private static final String  JDBC_IP_REGEX = "(\\d{1,3}\\.){3}\\d{1,3}";
	
	/**
	 * JDBC url 端口匹配表达式
	 */
	private static final String JDBC_PORT_REGEX = ":\\d{2,5}/";
	
	private GbaseExportStepMeta meta;
	private JdbcTemplate jdbcTemplate;
	public GbaseExportStep(StepMeta meta) {
		super(meta);
		this.meta=(GbaseExportStepMeta) meta;
	}

	@Override
	protected int handle() {
		int flag = StepState.RUNNING_SUCCESSED;
		String exportSql=DataCollectionUtils.getProperties("gbase_exportSql");
		if(StringUtils.isEmpty(exportSql)){
			meta.log("ERROR", "找不到gbase_exportSql配置");
			flag=StepState.RUNNING_FAILED;
		}
		jdbcTemplate = new JdbcTemplate(meta.getDsName());
		String sql=DpExecutorUtils.variableSubstitution(exportSql,meta);
		boolean isRemoteExport = isRemoteExport(sql); 
		File shellFile = null;
		try{
			if(isRemoteExport){
				String cmd = buildExportCmd(meta.getDsName(),sql);
				String shellPath = System.getProperty("java.io.tmpdir") +File.separator +SimpleKey.genShortUuid();
				meta.log("INFO","GBASE远程导出命令为 " + cmd +" ,导出脚本 " + shellPath);
				shellFile = new File(shellPath);
				FileUtils.writeStringToFile(shellFile, cmd);
				shellFile.setExecutable(true);
				Shell.execCommand(shellPath);
			}else{
				jdbcTemplate.execute(sql);
			}
		}catch(Exception e){
			meta.log("ERROR", "SQL执行异常：[{}]",sql);
			meta.log("ERROR", "异常信息：[{}]",e.getMessage());
			flag=StepState.RUNNING_FAILED;
		} finally{
			if(isRemoteExport){
				meta.log("INFO","清除导出脚本文件 " + shellFile.getAbsolutePath() + (shellFile.delete()?"成功":"失败")) ;
			}
		}
		
		return flag;
	}

	@Override
	public boolean stop() {
		// TODO Auto-generated method stub
		return false;
	}
	

	/**
	 * 根据sql中是否含有 {@link #REMOTE_EXPORT_FLAG}判断远程导出
	 * @param sql
	 * @return
	 * 	true:远程导出
	 * 	false:本地导出
	 */
	private boolean isRemoteExport(String sql){
		return sql.indexOf(REMOTE_EXPORT_FLAG) != -1;
	}
	
	
	/**
	 * 根据模板 gccli --no-defaults -u${username} -p${password} -h${hostName} -D${databaseName} -e "${exportSql}"构建命令
	 * @param dbName 数据库名
	 * @return
	 */
	private String buildExportCmd(String dbName,String exportSql){
		String exportCmd = DataCollectionUtils.getProperties("gbase.remote.exportCmd");
		DataSourceDefine dsDefine = DataSourceHolder.getInstance().getDsDefs().get(dbName);
		Map<String,String> dataMap = new HashMap<String, String>();
		dataMap.put("username", dsDefine.getUsername());
		dataMap.put("password", DesCipher.decrypt(dsDefine.getPassword()));
		dataMap.put("hostName",matchResult(dsDefine.getUrl(),JDBC_IP_REGEX));
		dataMap.put("port",getJdbcPort(dsDefine.getUrl()));
		dataMap.put("databaseName",getDataBaseName(dsDefine.getUrl()));
		dataMap.put("exportSql",exportSql);
		return DpExecutorUtils.variableSubstitution(exportCmd,dataMap);
	}
	
	/**
	 * 获取匹配的字符串结果
	 * @param str 原字符串
	 * @param reg 匹配的正则表达式
	 * @return 
	 * 	返回第一个匹配的结果，没有匹配则返回空字符串
	 */
	private String matchResult(String str,String reg){
		Pattern p = Pattern.compile(reg);
		Matcher m = p.matcher(str);
		if(m.find()){
			return m.group(0);
		}else{
			return "";
		}
	}
	
	/**
	 * 获取jdbc端口号
	 * @param jdbcUrl 
	 * @return
	 */
	private String getJdbcPort(String jdbcUrl){
		String port = matchResult(jdbcUrl,JDBC_PORT_REGEX);
		return port.substring(1,port.length()-1);
	}
	
	/**
	 * 获取gbaseurl中的数据库名
	 * <p> 截取最后一个 "/"符号后面的字符串为数据库名
	 * @param jdbcUrl
	 * @return
	 */
	private String getDataBaseName(String jdbcUrl){
		return jdbcUrl.substring(jdbcUrl.lastIndexOf("/")+1);
	}
}
